
#include "mymainwindow.h"
#include "openglframe.h"
#include "../enumtypes.h"

#include "captureSettingDlg.h"

#include <iostream>

using namespace std;

void printInfoAndExit() {
   
   cout<<endl;
   cout<<"Usage: CharAnim filename.{off | ply}"<<endl;
   cout<<"                [-skel skelname.skel]"<<endl;
   cout<<"                [-skin skinname.sb | skinname.sj]"<<endl;
   cout<<"                [-poses posesname.pss]"<<endl;
   exit(0);
}

/// Constructor.
MyMainWindow::MyMainWindow (QMainWindow *parent): QMainWindow(parent) 
{
   // Make sure the default opengl format includes stencil buffer and alpha.
   QGLFormat fmt;
   fmt.setAlpha(true);
   fmt.setStencil(true);
   QGLFormat::setDefaultFormat(fmt);
   
   // Executes the method which builds the remaining widgets of the window.
   // (Inherited from Ui::MainWindow)
   setupUi (this);
   
   timer = new QTimer(this);
   
   // Connect cut, paste, copy, zoom-in, zoom-out and zoom-all for openglframe
   connect(actionCut, SIGNAL(triggered()), this->glFrame, SLOT(cut()));
   connect(actionPaste, SIGNAL(triggered()), this->glFrame, SLOT(paste()));
   connect(actionCopy, SIGNAL(triggered()), this->glFrame, SLOT(copy()));    
   connect(actionZoomIn, SIGNAL(triggered()), this->glFrame, SLOT(zoomIn()));
   connect(actionZoomOut, SIGNAL(triggered()), this->glFrame, SLOT(zoomOut()));
   connect(actionZoomAll, SIGNAL(triggered()), this->glFrame, SLOT(zoomAll()));
   
   //~ connect(bPlay, SIGNAL(clicked()), this, SLOT(on_bPlay_clicked()));
   //~ connect(bStop, SIGNAL(clicked()), this, SLOT(on_bStop_clicked()));
   //~ connect(bPause, SIGNAL(clicked()), this, SLOT(on_bPause_clicked()));
   //~ connect(bRecord, SIGNAL(clicked()), this, SLOT(on_bRecord_clicked()));
   
   // Connect the slider 
   connect(sliderTime, SIGNAL(valueChanged(int)), this, SLOT(animateValueSlider()));
   
   // groupping exclusives actions 
   meshrenderGroup = new QActionGroup(this);
   meshrenderGroup->addAction(actionRenderPoints);
   meshrenderGroup->addAction(actionRenderWireframe);
   meshrenderGroup->addAction(actionRenderHiddenLines);
   meshrenderGroup->addAction(actionRenderFlatLines);
   meshrenderGroup->addAction(actionRenderFlat);
   meshrenderGroup->addAction(actionRenderTransparency);
   meshrenderGroup->addAction(actionRenderSmooth);
   
   rotationCompGroup = new QActionGroup(this);
   rotationCompGroup->addAction(actionAxisAngleRotation);
   rotationCompGroup->addAction(actionUnitQuaternionRotation);
   rotationCompGroup->addAction(actionLinearBlendingRotation);
   
   glFrame->setFocus();
}

void MyMainWindow::open(int argc, char *argv[]) {
   
   int carg = 2; // current argument
   int nargs = argc; // 
   if (nargs < 2) printInfoAndExit();
   
   open_model(QString(argv[1]));
   while (carg < nargs) {
      QString currstring = argv[carg++];
      if(currstring == "-skel") {
         currstring = argv[carg++];
         open_skeleton(currstring);
         continue;
      }
      if(currstring == "-skin") {
         currstring = argv[carg++];
         open_skinning(currstring);
         continue;
      }
      if(currstring == "-poses") {
         currstring = argv[carg++];
         open_poses(currstring);
         continue;
      }
      cout << "Unrecognized option: " << currstring.toStdString() << endl;
      printInfoAndExit();
   }
}

// Tries to load file if filename not empty.
void MyMainWindow::open_model(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      
      if (extension != "off" and extension != "ply") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < off|ply > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->loadShape(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      filenamemodel = filename;
      this->setWindowTitle("Character Animation using MLS - " + filenamemodel);
      // iconos relativos a acciones de una deformacion anterior son unchecked
      //~ resetItemsIcons();
   }
}

void MyMainWindow::open_skeleton(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      
      if (extension != "skel") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < skel > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->load_skeleton(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
   }
}

void MyMainWindow::open_skinning(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      if (extension != "sj" and extension != "sb") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < sb | sj > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->loadSkinning(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
   }
}

void MyMainWindow::open_poses(QString filename) {
   
   if (filename != "") {
      QFileInfo fi(filename);
      QString extension = fi.suffix();
      
      if (extension != "pss") {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension is not supported. \nYou must open < pss > format models.";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      
      //~ glFrame->clear();
      if (not glFrame->load_poses(filename)) {
         QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" format is incorrect";
         QMessageBox::critical(this, tr("Opening Error"), errorMsgFormat.arg(filename, extension));
         return;
      }
      else {
         // if poses loading is ok
         sliderTime->setMaximum(glFrame->poses.size());
      }
   }
}

/*
/// Automatically bound to the actionOpen menu item of the main window 
/// by the designer mechanism. Pops up a file open dialog for selecting
/// an "off" file.
void MyMainWindow::on_actionOpen_triggered() 
{
    // Asks for a file name to open.
    QString filename = QFileDialog::getOpenFileName (
                      this, 
                      tr("Choose a file"),
                      ".",
                      tr("Off meshes (*.off)"));
    
    // Tries to load file if filename not empty.
    if (filename != "") {
      //~ Polyhedron* poly = Polyhedron::load_off (filename.toStdString().c_str());
      //~ glFrame->addObject (poly, true);
      //~ glFrame->updateGL();
    }
}
*/

void MyMainWindow::on_actionSave_poses_as_triggered() {
   
   // Asks for a file name to save
   QString filename = QFileDialog::getSaveFileName(
                this, 
                tr("Save poses"),
                ".",
                tr("Poses files (*.pss)"));
    
   // Tries to save file if filename not empty.
   if (filename != "") {
      glFrame->saveAsPoses(filename);
   }
}

void MyMainWindow::on_actionSave_Current_Model_triggered() {
   cout<<"on_actionSave_Current_Model_as_triggered............................"<<endl;
   // Asks for a file name to save
   QString filename = QFileDialog::getSaveFileName(
                this, 
                tr("Save Mesh"),
                ".",
                tr("Model files (*.off)"));
    
   // Tries to save file if filename not empty.
   if (filename != "") {
      glFrame->saveShapeOFF(filename);
   }
}

/// Automatically bound to the actionSelect triggered event
/// by the designer mechanism. Enters selection mode.
void MyMainWindow::on_actionSelect_triggered() 
{
   glFrame->setInteractionMode(SELECT_MODE);
   //~ actionKey->setChecked(false);
   actionSelect->setChecked(true);
   actionRestriction->setChecked(false);
   actionAnimate->setChecked(false);
}

/// Automatically bound to the actionKey triggered event
/// by the designer mechanism. Enters keypoint insertion mode.
void MyMainWindow::on_actionKey_triggered() 
{
   glFrame->addKeyPoint();
   glFrame->updateGL();
   
    //~ glFrame->setInteractionMode (KEY_MODE);
    //~ actionKey->setChecked(true);
    //~ actionSelect->setChecked(false);
    //~ actionRestriction->setChecked(false);
    //~ actionAnimate->setChecked(false);
}

/// Automatically bound to the actionRestriction triggered event
/// by the designer mechanism. Enters restriction insertion mode.
void MyMainWindow::on_actionRestriction_triggered() 
{
    glFrame->setInteractionMode(RESTRICTION_MODE);
    //~ actionKey->setChecked(false);
    actionSelect->setChecked(false);
    actionRestriction->setChecked(true);
    actionAnimate->setChecked(false);
}

/// Automatically bound to the actionAnimate triggered event
/// by the designer mechanism. Enters animation mode.
void MyMainWindow::on_actionAnimate_triggered() 
{
    glFrame->setInteractionMode(ANIMATE_MODE);
    //~ glFrame->clearAnimationData();
    actionKey->setChecked(false);
    actionSelect->setChecked(false);
    actionRestriction->setChecked(false);
    actionAnimate->setChecked(true);
}

/// Groups selected objects.
void MyMainWindow::on_actionGroup_triggered ()
{
    glFrame->makeGroup ();
}

/// Ungroups selected objects.
void MyMainWindow::on_actionUngroup_triggered ()
{
    glFrame->breakGroup ();
}

void MyMainWindow::on_actionRenderPoints_triggered() {
   glFrame->meshRenderMode(POINTS);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderWireframe_triggered() {
   glFrame->meshRenderMode(WIREFRAME);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderFlat_triggered() {
   glFrame->meshRenderMode(FLAT);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderFlatLines_triggered() {
   glFrame->meshRenderMode(FLATLINES);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderHiddenLines_triggered() {
   glFrame->meshRenderMode(HIDDENLINES);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderSmooth_triggered() {
   glFrame->meshRenderMode(SMOOTH);
   glFrame->updateGL();
}

void MyMainWindow::on_actionRenderTransparency_triggered() {
   glFrame->meshRenderMode(TRANSPARENCY);
   glFrame->updateGL();
}

void MyMainWindow::on_actionLightOnOff_triggered() {
   if (actionLightOnOff->isChecked())
      actionLightOnOff->setIcon(QIcon(QString::fromUtf8("icons/lighton.png")));
   else 
      actionLightOnOff->setIcon(QIcon(QString::fromUtf8("icons/lightoff.png")));
   glFrame->lightingOnOff(actionLightOnOff->isChecked());
   glFrame->updateGL();
}

void MyMainWindow::on_actionProjection_triggered() {
   
   if (glFrame->isProjectionOrtho()) {
      const QString qstring("Perspective");
      actionProjection->setText(qstring);
      actionProjection->setIcon(QIcon(QString::fromUtf8("icons/perspective.png")));
      glFrame->orthographic(false);
   }
   else {
      const QString qstring("Orthographic");
      actionProjection->setText(qstring);
      actionProjection->setIcon(QIcon(QString::fromUtf8("icons/orthographic.png")));
      glFrame->orthographic(true);
   }
   
   glFrame->setGLview();
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewModel_triggered() {
   
   if (actionViewModel->isChecked())
      glFrame->viewItemOn(MODELDEF);
   else 
      glFrame->viewItemOff(MODELDEF);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewSkeleton_triggered() {
   
   if (actionViewSkeleton->isChecked())
      glFrame->viewItemOn(SKELETONDEF);
   else 
      glFrame->viewItemOff(SKELETONDEF);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewConstraints_triggered() {
   
   if (actionViewConstraints->isChecked())
      glFrame->viewItemOn(CONSTRAINTS);
   else 
      glFrame->viewItemOff(CONSTRAINTS);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewKeyPoints_triggered() {
   
   if (actionViewKeyPoints->isChecked())
      glFrame->viewItemOn(KEYPOINTS);
   else 
      glFrame->viewItemOff(KEYPOINTS);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewFloor_triggered() {
   
   if (actionViewFloor->isChecked())
      glFrame->viewItemOn(FLOOR);
   else 
      glFrame->viewItemOff(FLOOR);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewInfo_triggered() {
   
   if (actionViewInfo->isChecked())
      glFrame->viewItemOn(INFO);
   else 
      glFrame->viewItemOff(INFO);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewShadow_triggered() {
   
   if (actionViewShadow->isChecked())
      glFrame->viewItemOn(SHADOW);
   else 
      glFrame->viewItemOff(SHADOW);
   glFrame->updateGL();
}

void MyMainWindow::on_actionViewCurrentKeyPoint_triggered() {
   
   if (actionViewCurrentKeyPoint->isChecked())
      glFrame->viewItemOn(CURRENTKEYPOINT);
   else 
      glFrame->viewItemOff(CURRENTKEYPOINT);
   glFrame->updateGL();
}

/*
void MyMainWindow::on_actionNewPlay_triggered() {
   
   cout<<"xxxxxxxxxxxxxxxxxx on_actionNewPlay_triggered()"<<endl;
   
   if (actionViewInfo->isChecked()) {
      cout<<"if actionViewInfo->isChecked(): "<<glFrame->poses.size()<<endl;
      sliderTime->setMaximum(glFrame->poses.size());
      //~ glFrame->play();
      
      connect(timer, SIGNAL(timeout()), this,  SLOT(addValueSlider()));
      timer->start(0);
   }
   else {
      cout<<"else actionViewInfo->isChecked()"<<endl;
      sliderTime->setValue(0);
      disconnect(timer, 0, 0, 0);
   }
}
*/

void MyMainWindow::on_actionInsertClones_triggered() {
   
   bool ok;
   uint nclones = QInputDialog::getInteger(this, tr("Enter the number of clones"),
                                      tr("Number of clones:"), 0, 0, 100, 1, &ok);
   if (ok) {
      glFrame->buildModelClones(nclones);
   } else {
      // user pressed Cancel
   }
   
   glFrame->updateGL();
}

void MyMainWindow::on_bPlay_clicked() {
   
   sliderTime->setMaximum(glFrame->poses.size());
   //~ glFrame->play();
      
   connect(timer, SIGNAL(timeout()), this,  SLOT(addValueSlider()));
   timer->start(0);
   
   /// usando spatial keyframes 
   //~ sliderTime->setMaximum(glFrame->interKeyPoints.size());
   //~ glFrame->play();
   
   //~ connect(timer, SIGNAL(timeout()), this,  SLOT(addValueSlider()));
   //~ timer->start(0);
}

void MyMainWindow::on_bStop_clicked() {
   
   sliderTime->setValue(0);
   disconnect(timer, 0, 0, 0);
}

void MyMainWindow::on_bPause_clicked() {
   
   disconnect(timer, 0, 0, 0);
}

void MyMainWindow::on_bRecord_clicked() {
   
   if (bRecord->isChecked()) { 
      connect(timer, SIGNAL(timeout()), this->glFrame, SLOT(record()));
      bRecord->setIcon(QIcon(QString::fromUtf8("icons/player_recording.png")));
      //timer->start(0);
   }
   else {
      // desconectarlo do timer, so ele
      bRecord->setIcon(QIcon(QString::fromUtf8("icons/player_recordstart.png")));
      disconnect(timer, 0, 0, 0);
   }
}

void MyMainWindow::on_bCaptureDialog_clicked() {
   
   CaptureSettingDlg dlg;
   
   /// save pictures check box 
   if (glFrame->get_pic_capturing())
      dlg.cbSavePictures->setCheckState(Qt::Checked);
   else 
      dlg.cbSavePictures->setCheckState(Qt::Unchecked);
   
   /// save meshes check box 
   if (glFrame->get_mesh_capturing())
      dlg.cbSaveMeshes->setCheckState(Qt::Checked);
   else 
      dlg.cbSaveMeshes->setCheckState(Qt::Unchecked);
   
   int r = dlg.exec();
   if (r) {
      cout<<"click checked"<<endl;
      glFrame->set_pic_capturing((dlg.cbSavePictures->checkState()==Qt::Checked)? true:false);
      glFrame->set_mesh_capturing((dlg.cbSaveMeshes->checkState()==Qt::Checked)? true:false);
   }
   else {
   }
}

void MyMainWindow::addValueSlider() {
   
   if (sliderTime->value() < sliderTime->maximum())
      sliderTime->setValue(sliderTime->value()+1);
   else
      on_bStop_clicked();
   
   //~ if (sliderTime->value() < sliderTime->maximum())
      //~ sliderTime->setValue(sliderTime->value()+1); 
   //~ else
      //~ on_bStop_clicked();
}

void MyMainWindow::animateValueSlider() {
   
   //~ cout<<"sliderTime->value(): "<<sliderTime->value()<<endl;
   
   //~ glFrame->animate(sliderTime->value());
   glFrame->animate_poses(sliderTime->value()-1);
}

void MyMainWindow::on_actionResetAll_triggered () {
   
   glFrame->resetAll();
   glFrame->updateGL();
}

void MyMainWindow::on_actionAxisAngleRotation_triggered() {
   
   glFrame->setRotationCompTech(AXISANGLE);
   glFrame->executeDeformation();
   glFrame->updateGL();
}

void MyMainWindow::on_actionUnitQuaternionRotation_triggered() {
   
   glFrame->setRotationCompTech(UNITQUAT);
   glFrame->executeDeformation();
   glFrame->updateGL();
}

void MyMainWindow::on_actionLinearBlendingRotation_triggered() {
   
   glFrame->setRotationCompTech(BLENDINGROT);
   glFrame->executeDeformation();
   glFrame->updateGL();
}

// 
